# @Time    : 2022/9/23 10:29
# @Author  : 南黎
# @FileName: 3.rbf惩罚系数C的设置对模型性能.py

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from sklearn import preprocessing
from sklearn.datasets import load_iris # 导入鸢尾花数据集
from sklearn.svm import SVC #使用支持向量机算法


# 画出数据点和边界
def border_of_classifier(sklearn_cl, x, y):
        """
        param sklearn_cl : skearn 的分类器
        param x: np.array
        param y: np.array
        """
        ## 1 生成网格数据
        x_min, y_min = x.min(axis = 0) - 1
        x_max, y_max = x.max(axis = 0) + 1
        # 利用一组网格数据求出方程的值，然后把边界画出来。
        x_values, y_values = np.meshgrid(np.arange(x_min, x_max, 0.01),
        np.arange(y_min, y_max, 0.01))
        # 计算出分类器对所有数据点的分类结果 生成网格采样
        mesh_output = sklearn_cl.predict(np.c_[x_values.ravel(), y_values.ravel()])
        # 数组维度变形
        mesh_output = mesh_output.reshape(x_values.shape)
        fig, ax = plt.subplots(figsize=(16,10), dpi= 80)
        ## 会根据 mesh_output结果自动从 cmap 中选择颜色
        plt.pcolormesh(x_values, y_values, mesh_output, cmap = 'rainbow')
        plt.scatter(x[:, 0], x[:, 1], c = y, s=100, edgecolors ='steelblue' , linewidth = 1, cmap = plt.cm.Spectral)
        plt.xlim(x_values.min(), x_values.max())
        plt.ylim(y_values.min(), y_values.max())
        # 设置x轴和y轴
        plt.xticks((np.arange(np.ceil(min(x[:, 0]) - 1), np.ceil(max(x[:, 0]) + 1), 1.0)))
        plt.yticks((np.arange(np.ceil(min(x[:, 1]) - 1), np.ceil(max(x[:, 1]) + 1), 1.0)))


#封装一个模型训练函数，输入数据文件名即可完成训练
def my_train(datafile,C=1):
    data=pd.read_csv(datafile).values
    #数据归一化
    # max_abs_scaler = preprocessing.MaxAbsScaler()  # 注册一个预处理对象
    # data = max_abs_scaler.fit_transform(data)  # fit_transform(X[, y])	适合数据，然后转换它。
    X=data[:,0:2]
    y=data[:,2].astype('int')

    clf = SVC(C=C,kernel='rbf',decision_function_shape='ovr')#内核类型为rbf
    # C：浮动，可选（默认=1.0）误差项的惩罚参数 C。
    # kernel：指定要在算法中使用的内核类型。它必须是“linear”、“poly”、“rbf”、“sigmoid”、“precomputed”或可调用对象之一。如果没有给出，将使用 'rbf'。如果给定了可调用对象，则它用于从数据矩阵中预先计算内核矩阵；该矩阵应该是一个 shape 数组(n_samples, n_samples)。
    # linear：选择线性函数；
    # polynomial：选择多项式函数；
    # rbf：选择径向基函数；
    # sigmoid：选择 Logistics 函数作为核函数；
    # precomputed：使用预设核值矩阵，
    # SVC 类默认以径向基函数作为核函数。
    # decision_function_shape :默认决策函数分界线形状 ‘ovo’, ‘ovr’ or None, default=None
    # gamma: 高斯核函数,浮动，可选（默认='auto'）'rbf'、'poly' 和 'sigmoid' 的核系数。如果 gamma 为“auto”，则将使用 1/n_features。
    # fit_intercept：布尔值，默认值 真：指定是否应将常数（也称为偏差或截距）添加到决策函数中。

    # 训练模型,使用fit喂入数据X,y，即特征值和标签
    clf.fit(X, y)
    # 预测分类
    result=clf.predict(X)
    # 对模型进行评分
    score=clf.score(X,y)
    print(datafile+"rbf内核SVM评分",score)
    plt.figure()
    # 分割图1行1列第一个图
    plt.subplot(111)
    # 选择X特征1和特征2进行绘图
    # 原有的数据绘图
    plt.scatter(X[:,0],X[:,1],c =y.reshape((-1)),edgecolor='k',s=50)
    # 预测结果的绘图
    # plt.scatter(X[:,0],X[:,1],c =result.reshape((-1)),edgecolor='k',s=50)
    plt.savefig("3/" + "C={}{}文件原始数据图.png".format(C,datafile))
    plt.show()
    border_of_classifier(clf, X, y)
    plt.savefig("3/" + "C={}ex533{}".format(C, "rbf内核SVM分类图.png"))
    plt.show()

my_train("ex533.csv",C=0.01)
my_train("ex533.csv",C=10)
my_train("ex533.csv",C=1000)

